import sketch.SketchSequence;
import sketch.generator.GenTests;
import sketch.generator.JUnitTestCreator;
import sketch.generator.SequenceGenerator;
import sketch.skeleton.GeneratorMaps;
import sketch.skeleton.Skeleton;
import sketch.subject.TreeMap;
import sketch.util.Checker;
import junit.framework.TestCase;

public abstract class GenTest extends TestCase {
	
	private static int TEST_NUM = 0;
	
	public static String TEST_CASE_NAME = "testTreeMap";

	@Override
	public void setUp() {
		// this line should be able to set dynamically
		GenTests.reset(TreeMap.class);
	}

	/**
	 * The call back testing method by JUnit
	 * */
	public void testRunning() {
		@SuppressWarnings("rawtypes")
		GenTests genTests = new GenTests(this.testPath());
		
		while (genTests.numOfGenerators() == 0 || genTests.hasNextTest()) {
			System.out.println("---- start a new round for generating test: " + TEST_NUM + " ----");
			GeneratorMaps.resetCounter();

			//call the client method
			scratchTest();

			//check the validity of current test generator
			this.checkValidity(genTests);
			
			//generate a test
			SketchSequence generated = genTests.nextTest();
			System.out.println(JUnitTestCreator.createSingleTest(generated, TEST_CASE_NAME + (TEST_NUM++)));
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void checkValidity(GenTests genTests) {
		//the number of generators
		int numOfGeneratorsBeforeUpdate = genTests.numOfGenerators();
		//adding each generators
		for(SequenceGenerator<?> generator : GeneratorMaps.collectGenerators()) {
			if(!genTests.hasGenerator(generator)) {
				genTests.addGenerator(generator);
			}	
		}
		int numOfGeneratorsAfterUpdate = genTests.numOfGenerators();
		//do some checking here
		Checker.checkTrue(genTests.numOfGenerators() > 0, "The number of generators should > 0");
		if(numOfGeneratorsBeforeUpdate != 0) {
		  Checker.checkTrue(numOfGeneratorsBeforeUpdate == numOfGeneratorsAfterUpdate,
				  "The number of generators should not be changed");
		}
	}
	
	/**
	 * The place to provide inputs and initialize the tool
	 * */
	public abstract String testPath();

	/**
	 * The test which subclass needs to override
	 * */
	public abstract void scratchTest();
}
